package com.wei.czz.framework.security.filter;

import com.wei.czz.common.constant.Constant;
import com.wei.czz.common.enums.ResultEnum;
import com.wei.czz.common.enums.admin.user.RequestChannelEnum;
import com.wei.czz.common.exception.CzzException;
import com.wei.czz.common.utils.ContextUtils;
import com.wei.czz.common.utils.HttpUtils;
import com.wei.czz.common.utils.IPUtils;
import com.wei.czz.framework.common.service.SnowflakeService;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;

/**
 * Created by IntelliJ IDEA.
 *
 * @author wyw
 * date: 2024-06-12 10:41:23
 * className: HeaderFilter 请求头过滤器
 * version: 1.0
 * description:
 */
@Order(0)
@Component
@AllArgsConstructor
public class HeaderFilter extends OncePerRequestFilter {

    private static final Logger log = LoggerFactory.getLogger(HeaderFilter.class);

    private final SnowflakeService snowflakeService;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) {
        // 增加日志链路追踪代码
        String traceId = Long.toHexString(snowflakeService.get());
        MDC.put(Constant.TRACE_ID, traceId);
        MDC.put(Constant.SPAN_ID, traceId);
//        log.info("进入HeaderFilter {}", request.getRequestURI());

        try {
            // 获取请求源ip地址
            String requestIp = IPUtils.getRequestIp(request);
            log.info("解析请求来源得到请求ip：{}", requestIp);
            // 将请求源ip地址放到线程的上下文参数中
            ContextUtils.set(Constant.REQUEST_IP, requestIp);

            // 从请求头中获取token
            String token = request.getHeader(Constant.ACCESS_TOKEN);
            if (StringUtils.isEmpty(token)) {
                // 从请求参数中获取token
                token = request.getParameter(Constant.ACCESS_TOKEN);
                if (StringUtils.isNotEmpty(token)) {
                    // 对token进行解码
                    token = URLDecoder.decode(token, StandardCharsets.UTF_8);
                }
            }
            if (StringUtils.isNotBlank(token)) {
                // 将请求令牌设置到上下文参数中
                ContextUtils.set(Constant.ACCESS_TOKEN, token);
            }

            // 从请求头中获取刷新令牌
            String refreshToken = request.getHeader(Constant.REFRESH_TOKEN);
            if (StringUtils.isEmpty(refreshToken)) {
                // 从请求参数中获取refreshToken
                refreshToken = request.getParameter(Constant.REFRESH_TOKEN);
                if (StringUtils.isNotEmpty(refreshToken)) {
                    // 对refreshToken进行解码
                    refreshToken = URLDecoder.decode(refreshToken, StandardCharsets.UTF_8);
                }
            }
            if (StringUtils.isNotBlank(refreshToken)) {
                // 将刷新令牌设置到上下文参数中
                ContextUtils.set(Constant.REFRESH_TOKEN, refreshToken);
            }

            // 从请求头中获取请求渠道
            String channel = request.getHeader(Constant.REQUEST_CHANNEL);
            if (StringUtils.isEmpty(channel)) {
                // 从请求参数中获取请求渠道
                channel = request.getParameter(Constant.REQUEST_CHANNEL);
                if (StringUtils.isBlank(channel)) {
                    // 如果为传递请求渠道，则标记为未知来源请求
                    channel = RequestChannelEnum.UNKNOWN.getName();
                }
                // 对请求渠道进行解码
                channel = URLDecoder.decode(channel, StandardCharsets.UTF_8);
            }
            if (StringUtils.isNotBlank(channel)) {
                // 将请求渠道设置到上下文参数中
                ContextUtils.set(Constant.REQUEST_CHANNEL, channel);
            }

            // 请求放行
            filterChain.doFilter(request, response);

        } catch (CzzException e) {
            log.info("请求头过滤，抛出异常。code={} message={}", e.getCode(), e.getMessage());
            HttpUtils.setResponse(request, response, e.getCode(), e.getMessage());
        } catch (Exception e) {
            log.error("请求头过滤异常。message={}", e.getMessage(), e);
            // 设置返回结果
            HttpUtils.setResponse(request, response, ResultEnum.SERVICE_FAIL.getCode(),
                    ResultEnum.SERVICE_FAIL.getMsg());
        } finally {
            // 删除日志链路追踪代码
            MDC.clear();
            // 清理线程的上下文参数
            ContextUtils.remove();
        }
    }
}
